#pragma once

#include "../comm/net.hpp"
#include "../comm/message.hpp"
#include <future>

using namespace Message;
using namespace MuduoNet;
using namespace std;

namespace Client
{
    class Requestor
    {
    public:
        using ptr=shared_ptr<Requestor>;
        using RequestCallback = function<void(const BaseMessage::ptr&)>;
        using AsyncResponse = future<BaseMessage::ptr>;
        struct RequestDescribe
        {
            using ptr = shared_ptr<RequestDescribe>;
            BaseMessage::ptr request;
            RType rtype;
            promise<BaseMessage::ptr> response;
            RequestCallback callback;
          
        };
        void OnResponse(const BaseConnection::ptr &conn, BaseMessage::ptr &msg)
        {
            string rid=msg->GetRid();
            RequestDescribe::ptr rdp=GetDescribe(rid);
            if(rdp.get()==nullptr)
            {
                ELog("收到响应-%s,但是未找到对应的请求描述",rid.c_str());
                return ;
            }
            if(rdp->rtype==RType::REQ_ASYNC)
            {
                rdp->response.set_value(msg);
            }
            else if(rdp->rtype==RType::REQ_CALLBACK)
            {
                if(rdp->callback)   rdp->callback(msg);
            }
            else{
                ELog("请求类型未知");
            }
            DelDescribe(rid);//防止内存泄漏
        }
        bool Send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, AsyncResponse &async_rsp)
        {
            //异步请求发送
            RequestDescribe::ptr rdp=NewDescribe(req,RType::REQ_ASYNC);
            if(rdp.get()==nullptr)
            {
                ELog("构造请求描述对象失败!");
                return false;
            }
            if (conn) conn->Send(req);
            else {
                ELog("连接为空!");
                return false;
            }
            async_rsp=rdp->response.get_future();
            return true;
        }
        bool Send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req,  BaseMessage::ptr &rsp)
        {
            AsyncResponse rsp_future;
            bool ret=Send(conn,req,rsp_future);
            if(ret==false)
            {
                return false;
            }
            rsp=rsp_future.get();
            return true;

        }
        bool Send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, RequestCallback &cb)
        {
            RequestDescribe::ptr rdp=NewDescribe(req,RType::REQ_CALLBACK,cb);
            if(rdp.get()==nullptr)
            {
                ELog("构造请求描述对象失败!");
                return false;
            }
            conn->Send(req);
            return true;
        }

    private:
        RequestDescribe::ptr NewDescribe(const BaseMessage::ptr &req, RType rtype,
        const RequestCallback &cb=RequestCallback())
        {
            unique_lock<mutex> lock(_mutex);
            RequestDescribe::ptr rd=make_shared<RequestDescribe>();
            rd->request=req;
            rd->rtype=rtype;
            if(rtype==RType::REQ_CALLBACK&&cb)
            {
                rd->callback=cb;
            }
            _request_desc.insert(make_pair(req->GetRid(),rd));
            return rd;
        }
        RequestDescribe::ptr GetDescribe(const string &rid)
        {
            unique_lock<mutex> lock(_mutex);
            auto it=_request_desc.find(rid);
            if(it==_request_desc.end())
            {
                return RequestDescribe::ptr();
            }
            return it->second;
        }
        void DelDescribe(const string &rid)
        {
             unique_lock<mutex> lock(_mutex);
             _request_desc.erase(rid);
        }

    private:
        mutex _mutex;
        unordered_map<string, RequestDescribe::ptr> _request_desc;
    };
}